package me.ingxin.android.router.compiler.processor

import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.TypeSpec
import me.ingxin.android.router.annotaions.Interceptor
import me.ingxin.android.router.annotaions.compiler.LInterceptor
import me.ingxin.android.router.annotaions.compiler.LInterceptorIndex
import me.ingxin.android.router.compiler.util.*
import java.util.*
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.Modifier
import javax.lang.model.element.TypeElement
import javax.lang.model.util.ElementFilter

/**
 * Created by ingxin on 2022/4/15
 */
class InterceptorProcessor(processorUtil: ProcessorUtil, logger: Logger) :
    BaseProcessor(processorUtil, logger) {

    /**拦截器基类类型*/
    private val typeInterceptor =
        processorUtil.env.elementUtils.getTypeElement(INTERCEPTOR_NAME).asType()

    override fun getSupportedAnnotationTypes(): MutableSet<String> {
        return HashSet<String>().apply { add(Interceptor::class.java.name) }
    }

    /**
     * 解析[Interceptor]并生成需要处理的文件
     */
    fun process(env: RoundEnvironment) {
        val annotatedElements = env.getElementsAnnotatedWith(Interceptor::class.java) ?: return
        val list = ElementFilter.typesIn(annotatedElements) ?: return
        if (list.isNotEmpty()) {
            writeInterceptorIndex(list)
        }
    }

    fun getInterceptor(env: RoundEnvironment): List<LInterceptor>? {
        val annotatedElements = env.getElementsAnnotatedWith(Interceptor::class.java) ?: return null
        val list = ElementFilter.typesIn(annotatedElements) ?: return null
        if (list.isEmpty()) {
            return null
        }
        val tempMap = HashMap<String, LInterceptor>()
        for (item in list) {
            val lInterceptor = buildLInterceptor(item, tempMap)
            tempMap[lInterceptor.name] = lInterceptor
        }
        return tempMap.values.toList()
    }

    private fun buildLInterceptor(
        item: TypeElement,
        map: MutableMap<String, LInterceptor>
    ): LInterceptor {
        val annotation = item.getAnnotation(Interceptor::class.java)
        val className = item.qualifiedName.toString()

        if (!item.modifiers.contains(Modifier.PUBLIC)) {
            logger.throwException("[$className] modifier must be public!")
        }

        if (!processorUtil.env.typeUtils.isSubtype(item.asType(), typeInterceptor)) {
            //注解只能用在IInterceptor子类
            logger.throwException("[${className}] error, [@${Interceptor::class.java.simpleName}] annotation must be used at [${INTERCEPTOR_NAME}] or subtype!")
        }

        if (annotation.name.contains(" ")) {
            logger.throwException("[$className] error, annotation [@${Interceptor::class.java.simpleName}] name contains blank")
        }

        //name[id]重复
        if (map[annotation.name] != null) {
            logger.throwException("Duplicate interceptor name [${annotation.name}] found in class [${map[annotation.name]?.destination}] and class [$className]")
        }

        return LInterceptor(annotation.name, className, annotation.global, annotation.priority)
    }

    private fun writeInterceptorIndex(list: Set<TypeElement>) {
        //生成生成文件id
        val indexIdBuilder = StringBuilder()
        val arrayBuilder = CodeBlock.builder()
            .add("[\n")

        val tempMap = HashMap<String, LInterceptor>()
        for ((index, item) in list.withIndex()) {
            val lInterceptor = buildLInterceptor(item, tempMap)

            arrayBuilder.add(
                "%T(\"${lInterceptor.name}\",·\"${lInterceptor.destination}\",·${lInterceptor.global},·${lInterceptor.priority})",
                LInterceptor::class
            )

            if (index != list.size - 1) {
                arrayBuilder.add(",")
            }
            arrayBuilder.add("\n")

            //拼接id
            indexIdBuilder.append(lInterceptor.destination.replace(".", "_")).append("_")
            tempMap[lInterceptor.name] = lInterceptor
        }
        tempMap.clear()

        arrayBuilder.add("]")

        //生成路由表注解
        val annotationSpec = AnnotationSpec.builder(LInterceptorIndex::class)
            .addMember(arrayBuilder.build())
            .build()

        //将唯一id转化成uuid的形式
        val indexId = indexIdBuilder.substring(0, indexIdBuilder.length - 1)
        val indexName = "${INTERCEPTOR_INDEX_NAME_PREFIX}${
            UUID.nameUUIDFromBytes(indexId.toByteArray()).toString().replace("-", "_")
        }"

        //生成类
        val classSpec = TypeSpec.classBuilder(indexName)
            .addAnnotation(annotationSpec)
            .build()

        //创建类文件
        processorUtil.writeClass(INTERCEPTOR_INDEX_PACKAGE_NAME, classSpec)
    }


}